﻿using System;
using System.ComponentModel;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Text;
using PinLib;
using pinlib.structs;

namespace pinlib.functions
{
    internal class User32M
    {

        /// <summary>
        ///   Calculates the required size of the window rectangle, based on the desired client-rectangle size
        /// </summary>
        /// <param name = "windowRect">Client area of the desired window</param>
        /// <param name = "style">The window style of the window whose required size is to be calculated. You cannot specify the WS_OVERLAPPED style.</param>
        /// <param name = "hasMenu">Indicates whether the window has a menu</param>
        /// <returns>the coordinates of the top-left and bottom-right corners of the window to accommodate the
        ///   desired client area</returns>
        public static Rectangle AdjustWindowRectM(Rectangle windowRect, Enumerations.WindowStyles style, bool hasMenu)
        {
            try
            {
                Rectangle mRect = new Rectangle();
                /* unmanaged RECT */
                GDIStructures.RECT nRect = new GDIStructures.RECT();
                /* convert the incoming rectangle into a RECT */
                Conversions.RectangleToRECT(windowRect, ref nRect);

                User32Native.AdjustWindowRect(ref nRect, (uint)style, hasMenu);

                /* Convert unmanaged REC for return */
                Conversions.RECTtoRectangle(nRect, ref mRect);

                return mRect;
            }
            catch (Win32Exception err)
            {
                throw new Win32Exception(err.Message, err.GetBaseException());
            }
        }

        /// <summary>
        ///   Enables you to produce special effects when showing or hiding windows. 
        ///   There are four types of animation: roll, slide, collapse or expand, and alpha-blended fade.
        /// </summary>
        /// <param name = "hWnd">A handle to the window to animate. The calling thread must own this window</param>
        /// <param name = "duration">The time it takes to play the animation, in milliseconds. Typically, an animation takes 200 milliseconds to play.</param>
        /// <param name = "animation">The type of animation</param>
        /// <returns>success=nonzero, fail=zero</returns>
        public static bool AnimateWindowM(IntPtr hWnd, UInt32 duration, AnimateWindowCommands animation)
        {
            try
            {
                return User32Native.AnimateWindow(hWnd, duration, (UInt32)animation);
            }
            catch (Win32Exception err)
            {
                throw new Win32Exception(err.Message, err.GetBaseException());
            }
        }

        /// <summary>
        ///   Arranges all the minimized (iconic) child windows of the specified parent window
        /// </summary>
        /// <param name = "hWnd">A handle to the parent window</param>
        /// <returns>success = the height of one row of icons, fail = 0</returns>
        public static uint ArrangeIconicWindowsM(IntPtr hWnd)
        {
            try
            {
                return User32Native.ArrangeIconicWindows(hWnd);
            }
            catch (Win32Exception err)
            {
                throw new Win32Exception(err.Message, err.GetBaseException());
            }
        }

        /// <summary>
        ///   Brings the specified window to the top of the Z order. If the window is a top-level window,
        ///   it is activated. If the window is a child window, the top-level parent window associated
        ///   with the child window is activated
        /// </summary>
        /// <param name = "hWnd">A handle to the window to bring to the top of the Z order</param>
        /// <returns>If the function succeeds, the return value is nonzero.</returns>
        public static bool BringWindowToTopM(IntPtr hWnd)
        {
            try
            {
                return User32Native.BringWindowToTop(hWnd);
            }
            catch (Win32Exception err)
            {
                throw new Win32Exception(err.Message, err.GetBaseException());
            }
        }

        /// <summary>
        ///   Modifies the User Interface Privilege Isolation (UIPI) message filter for a specified window
        /// </summary>
        /// <param name = "hWnd">A handle to the window whose UIPI message filter is to be modified</param>
        /// <param name = "message">The message that the message filter allows through or blocks</param>
        /// <param name = "action">The action to be performed from the MessageFilterAction enumeration</param>
        /// <returns>CHANGEFILTERSTRUCT</returns>
        public static CHANGEFILTERSTRUCT ChangeWindowMessageFilterExM(IntPtr hWnd, AnimateWindowCommands message, MessageFilterAction action)
        {
            CHANGEFILTERSTRUCT cfs = new CHANGEFILTERSTRUCT();
            cfs.CbSize = (UInt32)Marshal.SizeOf(cfs);

            try
            {
                User32Native.ChangeWindowMessageFilterEx(hWnd, (uint)message, (uint)action, ref cfs);
                return cfs;
            }
            catch (Win32Exception err)
            {
                throw new Win32Exception(err.Message, err.GetBaseException());
            }
        }

        /// <summary>
        ///   Determines which, if any, of the child windows belonging to a parent window contains the specified point.
        ///   The search is restricted to immediate child windows. Grandchildren, and deeper descendant windows are not
        ///   searched
        /// </summary>
        /// <param name = "hwnd">A handle to the parent window</param>
        /// <param name = "mPoint">System.Point that defines the client coordinates, relative to hwnd,
        ///   of the point to be checked</param>
        /// <returns>The return value is a handle to the child window that contains the point, even if the child window is hidden or disabled.
        ///   If the point lies outside the parent window, the return value is NULL.</returns>
        public static IntPtr ChildWindowFromPointM(IntPtr hwnd, Point mPoint)
        {
            try
            {
                return User32Native.ChildWindowFromPoint(hwnd, new GDIStructures.POINT(mPoint.X, mPoint.Y));
            }
            catch (Win32Exception err)
            {
                throw new Win32Exception(err.Message, err.GetBaseException());
            }
        }

        /// <summary>
        /// Determines which, if any, of the child windows belonging to the specified parent window contains the specified
        /// point. The function can ignore invisible, disabled, and transparent child windows. The search is restricted to
        /// immediate child windows. Grandchildren and deeper descendants are not searched
        /// </summary>
        /// <param name="hwnd">A handle to the parent window.</param>
        /// <param name="pt">System.Point that defines the client coordinates, relative to hwnd,
        /// of the point to be checked</param>
        /// <param name="wfpFlag">The child windows to be skipped</param>
        /// <returns>
        /// The return value is a handle to the first child window that contains the point and meets the criteria
        /// specified by uFlags. If the point is within the parent window but not within any child window that meets the
        /// criteria, the return value is a handle to the parent window. If the point lies outside the parent window or
        /// if the function fails, the return value is NULL
        /// </returns>
        public static IntPtr ChildWindowFromPointExM(IntPtr hwnd, Point pt, WindowFromPointFlags wfpFlag)
        {
            try
            {
                return User32Native.ChildWindowFromPointEx(hwnd, new GDIStructures.POINT(pt.X, pt.Y), (Int32)wfpFlag);
            }
            catch (Win32Exception err)
            {
                throw new Win32Exception(err.Message, err.GetBaseException());
            }
        }

        /// <summary>Destroys the specified window</summary>
        /// <param name="hWnd">A handle to the window to be destroyed</param>
        /// <returns>If the function succeeds, the return value is nonzero</returns>
        /// <exception cref="System.ComponentModel.Win32Exception">Throws an exception for a Win32 error code.</exception>
        public static bool DestroyWindowM(IntPtr hWnd)
        {
            try
            {
                return User32Native.DestroyWindow(hWnd);
            }
            catch (Win32Exception err)
            {
                throw new Win32Exception(err.Message, err.GetBaseException());
            }
        }

        /// <summary>
        /// Retrieves a handle to the top-level window whose class name and window name match the specified strings.
        /// This function does not search child windows. This function does not perform a case-sensitive search.
        /// </summary>
        /// <param name="className">The full window class name. or empty string for null</param>
        /// <param name="title">The window name (the window's title). If this parameter is an empty string, all window names match.</param>
        /// <returns>
        /// If the function succeeds, the return value is a handle to the window that has the specified class name and window name
        /// </returns>
        /// <exception cref="System.ComponentModel.Win32Exception">Throws an exception for a Win32 error code.</exception>
        public static IntPtr FindWindowM(string className, string title)
        {
            try
            {
                return User32Native.FindWindow(className, title);
            }
            catch (Win32Exception err)
            {
                throw new Win32Exception(err.Message, err.GetBaseException());
            }
        }

        /// <summary>Retrieves information about the specified window</summary>
        /// <param name="hWnd">Handle to the window to query</param>
        /// <returns>A WINDOWINFO structure</returns>
        /// <exception cref="Win32Exception">Throws an exception for a Win32 error code.</exception>
        public static WINDOWINFO GetWindowInfoM(IntPtr hWnd)
        {
            WINDOWINFO windowinfo = new WINDOWINFO();
            try
            {
                User32Native.GetWindowInfo(hWnd, ref windowinfo);
            }
            catch (Win32Exception err)
            {
                throw new Win32Exception(err.Message, err.GetBaseException());
            }
            return windowinfo;
        }

        /// <summary>
        /// Retrieves the dimensions of the bounding rectangle of the specified window.
        /// The dimensions are given in screen coordinates that are relative to the upper-left corner of the screen
        /// </summary>
        /// <param name="hwnd">A handle to the window</param>
        /// <returns>
        /// the screen coordinates of the upper-left and lower-right corners of the window
        /// </returns>
        public static Rectangle GetWindowRectM(IntPtr hwnd)
        {
            Rectangle mRect = new Rectangle();

            try
            {
                GDIStructures.RECT nRect;
                User32Native.GetWindowRect(hwnd, out nRect);
                Conversions.RECTtoRectangle(nRect, ref mRect);
            }
            catch (Win32Exception err)
            {
                throw new Win32Exception(err.Message, err.GetBaseException());
            }

            return mRect;
        }

        /// <summary></summary>
        /// <param name="hWnd">Handle to the window to query</param>
        /// <returns>Class name of window</returns>
        /// <exception cref="System.ComponentModel.Win32Exception">Throws an exception for a Win32 error code.</exception>
        public static string RealGetWindowClassM(IntPtr hWnd)
        {
            StringBuilder sb = new StringBuilder();
            try
            {
                User32Native.RealGetWindowClass(hWnd, sb, (uint)Marshal.SizeOf(sb));
            }
            catch (Win32Exception err)
            {
                throw new Win32Exception(err.Message, err.GetBaseException());
            }
            return sb.ToString();
        }

        /// <summary>
        /// Changes the text of the specified window's title bar (if it has one). If the specified window is a control, the text of the control is changed.
        /// However, SetWindowText cannot change the text of a control in another application
        /// </summary>
        /// <param name="hWnd">A handle to the window or control whose text is to be changed</param>
        /// <param name="newText">The new title or control text</param>
        /// <returns>If the function succeeds, the return value is nonzero</returns>
        /// <exception cref="System.ComponentModel.Win32Exception">Throws an exception for a Win32 error code.</exception>
        public static bool SetWindowTextM(IntPtr hWnd, string newText)
        {
            try
            {
                return User32Native.SetWindowText(hWnd, newText);
            }
            catch (Win32Exception err)
            {
                throw new Win32Exception(err.Message, err.GetBaseException());
            }
        }


        /// <summary>
        /// Sets the show state of a window created by a different thread.
        /// </summary>
        /// <param name="hWnd">A handle to the window</param>
        /// <param name="showType">Controls how the window is to be shown. For a list of possible values, see the <see cref="CmdShow"/>CmdShow enumeration</param>
        /// <returns>
        /// If the window was previously visible, the return value is nonzero. If the window was previously hidden, the return value is zero
        /// </returns>
        /// <exception cref="System.ComponentModel.Win32Exception">Throws an exception for a Win32 error code.</exception>
        public static bool ShowWindowAsyncM(IntPtr hWnd, CmdShow showType)
        {
            try
            {
                return User32Native.ShowWindowAsync(hWnd, (int)showType);
            }
            catch (Win32Exception err)
            {
                throw new Win32Exception(err.Message, err.GetBaseException());
            }
        }

        /// <summary>
        /// Retrieves a handle to the window that contains the specified point
        /// </summary>
        /// <param name="mPoint">The System.Point to be checked</param>
        /// <returns>
        /// The return value is a handle to the window that contains the point.
        /// If no window exists at the given point, the return value is NULL.
        /// If the point is over a static text control, the return value is a handle to the
        /// window under the static text control
        /// </returns>
        public static IntPtr WindowFromPointM(Point mPoint)
        {
            try
            {
                return User32Native.WindowFromPoint(new GDIStructures.POINT(mPoint.X, mPoint.Y));
            }
            catch (Win32Exception err)
            {
                throw new Win32Exception(err.Message, err.GetBaseException());
            }
        }

        /// <summary>Retrieves the cursor's position, in screen coordinates</summary>
        /// <returns>A managed Point structure</returns>
        public static Point GetCursorPosM()
        {
            GDIStructures.POINT lpPoint;
            User32Native.GetCursorPos(out lpPoint);

            return lpPoint;
        }

        /// <summary>
        /// Enables an application to customize the system cursors. It replaces the contents
        /// of the system cursor specified by the cursorStyle parameter with the contents of the cursor
        /// specified by the hWndCursor parameter and then destroys hWndCursor.
        /// </summary>
        /// <param name="hWndCursor">A handle to the cursor</param>
        /// <param name="cursorStyle">Style of cursor to load</param>
        public static void SetSystemCursorM(IntPtr hWndCursor, Enumerations.CursorStyle cursorStyle)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Loads the specified cursor resource from the executable (.EXE) file associated with an application instance
        /// </summary>
        /// <param name="hWndCursor">A handle to an instance of the module whose executable file contains the cursor to be loaded</param>
        /// <param name="cursorStyle">Style of cursor to load</param>
        /// <returns>
        /// If the function succeeds, handle to the newly loaded cursor.If it fails, the return value is NULL
        /// </returns>
        public static IntPtr LoadCursorM(IntPtr hWndCursor, Enumerations.CursorStyle cursorStyle)
        {
            return User32Native.LoadCursor(hWndCursor, (int)cursorStyle);
        }

        /// <summary>
        /// Destroys a cursor and frees any memory
        /// the cursor occupied. Do not use this function to destroy a shared cursor
        /// </summary>
        /// <param name="iconHandle">A handle to the cursor to be destroyed. The cursor must not be in use</param>
        /// <returns>Zero on fail, non-zero on success</returns>
        public static bool DestroyIconM(IntPtr iconHandle)
        {
            return User32Native.DestroyIcon(iconHandle);
        }



    }
}